package org.seanye.erp.view;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.seanye.erp.NLSTO;
import org.seanye.erp.view.actions.AddNextWeekAction;
import org.seanye.erp.view.actions.AddPrivWeekAction;
import org.seanye.erp.view.actions.DeleteWeekAction;
import org.seanye.erp.view.model.Store;
import org.seanye.erp.view.model.StoreItem;
import org.seanye.erp.view.model.WeekStore;
import org.seanye.erp.view.util.DateUtil;
import org.seanye.erp.view.util.DoubleUtil;

public class View extends ViewPart {

    private static final String PROPERTY = "Property_";
    private static final String DEFAULT_DOUBLE_STRING = "0";
    private static final String BLANK = "";
    private static final Color WARN_COLOR = Display.getCurrent()
	    .getSystemColor(SWT.COLOR_RED);

    public static final String ID = "org.seanye.erp.view.View";

    private TableViewer viewer;

    private static final int BALANCE_INDEX = 12;
    private static ColumnConfig[] columns = new ColumnConfig[] {
	    new ColumnConfig(100, NLSTO.Store_Date),
	    new ColumnConfig(80, NLSTO.Store_Previous),
	    new ColumnConfig(80, NLSTO.Store_Week_Input),
	    new ColumnConfig(80, NLSTO.Store_Week_Total_Stock),
	    new ColumnConfig(80, NLSTO.Week_Mon),
	    new ColumnConfig(80, NLSTO.Week_Tue),
	    new ColumnConfig(80, NLSTO.Week_Wen),
	    new ColumnConfig(80, NLSTO.Week_Thr),
	    new ColumnConfig(80, NLSTO.Week_Fri),
	    new ColumnConfig(80, NLSTO.Week_Sat),
	    new ColumnConfig(80, NLSTO.Week_Sun),
	    new ColumnConfig(100, NLSTO.Store_Week_Out_Total_Stock),
	    new ColumnConfig(100, NLSTO.Store_Week_Balance),
	    new ColumnConfig(100, NLSTO.Store_Week_Warn) };
    static {
	int i = 0;
	for (ColumnConfig config : columns) {
	    config.property = PROPERTY + i;
	    i++;
	}
    }
    private String[] PROPERTIES = new String[columns.length];

    private Store store;

    /**
     * The content provider class is responsible for providing objects to the
     * view. It can wrap existing objects in adapters or simply return objects
     * as-is. These objects may be sensitive to the current input of the view,
     * or ignore it and always show the same content (like Task List, for
     * example).
     */
    class ViewContentProvider implements IStructuredContentProvider {

	public void inputChanged(Viewer v, Object oldInput, Object newInput) {
	}

	public void dispose() {
	}

	public Object[] getElements(Object parent) {
	    if (parent instanceof Store) {
		for (WeekStore s : ((Store) parent).getStores()) {
		    s.addPropertyChangeListener(createListener(s));
		}
		return ((Store) parent).getStores().toArray(new Object[0]);
	    }
	    return new Object[] {};
	}

	private PropertyChangeListener createListener(final WeekStore weekStore) {
	    return new PropertyChangeListener() {
		public void propertyChange(PropertyChangeEvent evt) {
		    // compare balance with warn Number
		    TableItem ti = null;
		    TableItem[] items = viewer.getTable().getItems();
		    for (TableItem item : items) {
			if (item.getData().equals(weekStore)) {
			    ti = item;
			}
		    }
		    if (weekStore.getBalance() <= weekStore.getWarnNumber()
			    && ti != null) {
			ti.setForeground(BALANCE_INDEX, WARN_COLOR);
		    } else {
			ti.setForeground(12, Display.getCurrent()
				.getSystemColor(SWT.COLOR_BLACK)); // reset to
			// blank
		    }
		}
	    };
	}
    }

    class ViewLabelProvider extends LabelProvider implements
	    ITableLabelProvider {
	public String getColumnText(Object obj, int index) {
	    return getValueForClolumnIndex((WeekStore) obj, index);
	}

	public Image getColumnImage(Object obj, int index) {
	    if (index == 0) {
		return getImage(obj);
	    } else
		return null;
	}

	@Override
	public Image getImage(Object obj) {
	    return PlatformUI.getWorkbench().getSharedImages().getImage(
		    ISharedImages.IMG_TOOL_PASTE);
	}
    }

    private String getValueForClolumnIndex(final WeekStore store,
	    final int index) {
	switch (index) {
	case 0:
	    return DateUtil.format(store.getStartDate());
	case 1:
	    return DoubleUtil.showDouble(store.getPrviousWeekTotal());
	case 2:
	    return DoubleUtil.showDouble(store.getInput());
	case 3:
	    return DoubleUtil.showDouble(store.getTotalStock());
	    // 4-10 is week index
	case 4:
	case 5:
	case 6:
	case 7:
	case 8:
	case 9:
	case 10:
	    try {
		StoreItem dayItem = store.getWeekItems().get(index - 2);
		if (dayItem != null) {
		    return DoubleUtil.showDouble(dayItem.getShipment());
		}
	    } catch (Exception e) {
		return DEFAULT_DOUBLE_STRING;
	    }
	case 11:
	    return DoubleUtil.showDouble(store.totalShipment());
	case 12:
	    return DoubleUtil.showDouble(store.getBalance());
	case 13:
	    return DoubleUtil.showDouble(store.getWarnNumber());
	default:
	    return BLANK;
	}
    }

    /**
     * This is a callback that will allow us to create the viewer and initialize
     * it.
     */
    @Override
    public void createPartControl(Composite parent) {
	viewer = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL
		| SWT.FULL_SELECTION);
	viewer.getTable().setHeaderVisible(true);
	viewer.getTable().setLinesVisible(true);
	viewer.setUseHashlookup(true);

	int i = 0;
	for (ColumnConfig columnConfig : columns) {
	    createColumn(columnConfig);
	    PROPERTIES[i] = columnConfig.property;
	    i++;
	}

	viewer.setContentProvider(new ViewContentProvider());
	viewer.setLabelProvider(new ViewLabelProvider());

	viewer.setColumnProperties(PROPERTIES);
	viewer.setCellEditors(createCellEditors());
	viewer.setCellModifier(createCellModifier());

	store = Store.createDefaultStore();
	viewer.setInput(store);

	createMenu();

    }

    private void createMenu() {
	MenuManager mgr = new MenuManager("popupMenu");
	mgr.addMenuListener(new IMenuListener() {
	    public void menuAboutToShow(IMenuManager manager) {
		IContributionItem[] items = manager.getItems();
		for (IContributionItem item : items) {
		    ActionContributionItem actionItem = (ActionContributionItem) item;
		    IAction action = actionItem.getAction();
		    action.setEnabled(action.isEnabled());
		}
	    }
	});
	mgr.add(new AddNextWeekAction(viewer, store));
	mgr.add(new AddPrivWeekAction(viewer, store));
	mgr.add(new DeleteWeekAction(viewer, store));
	Menu menu = mgr.createContextMenu(viewer.getTable());
	viewer.getTable().setMenu(menu);
    }

    private ICellModifier createCellModifier() {
	return new ICellModifier() {

	    public void modify(Object element, String property, Object value) {
		if (element instanceof Item) {
		    List<String> list = Arrays.asList(PROPERTIES);
		    TableItem item = (TableItem) element;
		    WeekStore store = (WeekStore) item.getData();
		    String str = (String) value;
		    int index = list.indexOf(property);
		    switch (index) {
		    case 0:
			// verify date;
			try {
			    Date date = DateUtil.getFirstDayOfWeek(str);
			    store.setStartDate(date);
			} catch (Exception e) {
			    MessageDialog.openWarning(getSite().getShell(),
				    "Edit", e.getMessage());
			}
			break;
		    case 1:
			try {
			    store.setPrviousWeekTotal(Double.parseDouble(str));
			} catch (Exception e) {
			    promptInvalid(str);
			}
			break;
		    case 2:
			try {
			    store.setInput(Double.parseDouble(str));
			} catch (Exception e) {
			    promptInvalid(str);
			}
			break;
		    case 3:
			// Edit disable
			break;
		    case 4:
		    case 5:
		    case 6:
		    case 7:
		    case 8:
		    case 9:
		    case 10:
			List<StoreItem> weekItems = store.getWeekItems();
			Date currentDate = Calendar.getInstance().getTime();
			try {
			    StoreItem si = weekItems.get(index - 2);
			    si.setUpdatedDate(currentDate);
			    try {
				si.setShipment(Double.parseDouble(str));
			    } catch (Exception e) {
				promptInvalid(str);
			    }
			} catch (Exception e) {
			    StoreItem si = new StoreItem(currentDate);
			    try {
				si.setShipment(Double.parseDouble(str));
			    } catch (Exception ee) {
				promptInvalid(str);
			    }
			    weekItems.add(index - 2, si);
			}
			break;
		    case 11:
			// Edit disable
			break;
		    case 12:
			// Edit disable
			break;
		    case 13:
			try {
			    store.setWarnNumber(Double.parseDouble(str));
			} catch (Exception ee) {
			    promptInvalid(str);
			}
		    default:
			break;
		    }
		    viewer.update(store, PROPERTIES);
		}
	    }

	    private void promptInvalid(String str) {
		MessageDialog.openWarning(getSite().getShell(), "Edit", str
			+ " is not a valid double value");
	    }

	    public Object getValue(Object element, String property) {
		WeekStore weekStore = null;
		if (element instanceof Item) {
		    weekStore = (WeekStore) ((Item) element).getData();
		} else if (element instanceof WeekStore) {
		    weekStore = (WeekStore) element;
		}
		if (weekStore == null) {
		    return BLANK;
		} else {
		    List<String> list = Arrays.asList(PROPERTIES);
		    return getValueForClolumnIndex(weekStore, list
			    .indexOf(property));
		}
	    }

	    public boolean canModify(Object element, String property) {
		List<String> list = Arrays.asList(PROPERTIES);
		switch (list.indexOf(property)) {
		case 3:
		case 11:
		case 12:
		    return false;
		default:
		    return true;
		}
	    }
	};
    }

    private CellEditor[] createCellEditors() {
	CellEditor[] editors = new CellEditor[viewer.getTable()
		.getColumnCount()];
	for (int i = 0; i < editors.length; i++) {
	    TextCellEditor textCellEditor = new TextCellEditor(viewer
		    .getTable());
	    ((Text) textCellEditor.getControl()).setTextLimit(60);
	    textCellEditor.setStyle(SWT.BORDER);
	    editors[i] = textCellEditor;
	}
	return editors;
    }

    private void createColumn(ColumnConfig config) {
	TableColumn column = new TableColumn(viewer.getTable(), SWT.NONE
		| SWT.RESIZE);
	column.setWidth(config.width);
	column.setText(config.name);
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    @Override
    public void setFocus() {
	viewer.getControl().setFocus();
    }

    static class ColumnConfig {
	private int width;
	private String name;
	private String property;

	public ColumnConfig(int width, String name) {
	    super();
	    this.width = width;
	    this.name = name;
	}
    }
    
    
}